home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmigaPlus / Tools / Development / envCPP31 / c++ / tools / makemake / source / main.c next >
Encoding:
C/C++ Source or Header  |  2002-01-01  |  48.5 KB  |  1,849 lines

  1. /* --------------------------------- makemake ----------------------------------
  2.  
  3.  makemake (derived from LFMakeMaker by Laurent Faillie)
  4.  
  5.  SAS/C:
  6.  
  7.  sc main.c
  8.  
  9. */
  10.  
  11. /// "compiler"
  12.  
  13. #ifdef __SASC
  14.  
  15. #define __USE_SYSBASE
  16. #define __geta4      __saveds
  17. #define __stkargs    __stdargs
  18.  
  19. #define __A0         register __a0
  20. #define __A1         register __a1
  21. #define __A2         register __a2
  22. #define __A3         register __a3
  23. #define __A4         register __a4
  24. #define __A5         register __a5
  25. #define __A6         register __a6
  26. #define __A7         register __a7
  27. #define __D0         register __d0
  28. #define __D1         register __d1
  29. #define __D2         register __d2
  30. #define __D3         register __d3
  31. #define __D4         register __d4
  32. #define __D5         register __d5
  33. #define __D6         register __d6
  34. #define __D7         register __d7
  35.  
  36. #endif
  37.  
  38. #ifdef _DCC
  39.  
  40. #define __asm
  41.  
  42. #endif
  43.  
  44. ///
  45. /// "includes"
  46.  
  47. #include <string.h>
  48. #include <stdio.h>
  49. #include <string.h>
  50. #include <stdlib.h>
  51. #include <stdarg.h>
  52. #include <ctype.h>
  53. #include <errno.h>
  54. #include <unistd.h>
  55. #include <exec/exec.h>
  56. #include <dos/dos.h>
  57. #include <dos/dosextens.h>
  58. #include <dos/rdargs.h>
  59. #include <dos/dostags.h>
  60.  
  61. // prototypes
  62.  
  63. #include <clib/alib_protos.h>
  64. #include <clib/dos_protos.h>
  65. #include <clib/exec_protos.h>
  66. #include <clib/utility_protos.h>
  67.  
  68. // pragmas
  69.  
  70. #ifdef __SASC
  71.  
  72. #include <pragmas/dos_pragmas.h>
  73. #include <pragmas/exec_sysbase_pragmas.h>
  74. #include <pragmas/intuition_pragmas.h>
  75. #include <pragmas/utility_pragmas.h>
  76. #include <pragmas/wb_pragmas.h>
  77.  
  78. #endif
  79.  
  80. ///
  81. /// "defines"
  82.  
  83. #define PATH_MAX  512                                // maximum path length
  84. #define DEFLINE   128                                // default line length (in fact DEFLINE + 2)
  85. #define DEFTAB    8                                  // width of a TAB character
  86. #define COMPILE   "vc -c -o %obj %src"               // command line for creating objects
  87. #define LINK      "vc -o %exe %objs"                 // command line for creating executable
  88.  
  89. // flags for makefile generation
  90.  
  91. #define GENERATE_EXEC    (1L<<0)
  92. #define GENERATE_OBJECT  (1L<<1)
  93. #define GENERATE_FORCE   (1L<<2)                     // do not check ltargets
  94.  
  95. #ifdef __SASC
  96.  
  97. UBYTE Version[] = "$VER: makemake 1.0 " __AMIGADATE__ "\n\0";
  98.  
  99. #else
  100.  
  101. UBYTE Version[] = "$VER: makemake 1.0 (" __COMMODORE_DATE__ ")\n\0";
  102.  
  103. #endif
  104.  
  105. UBYTE About[] = "makemake 1.0 (mail@dietmar-eilert.de)\n";
  106.  
  107. // command line options
  108.  
  109. #define TEMPLATE "COMPILE/K,LINK/K,FILES/M/A,IGNORE/K,LOCAL/S,GLOBAL/S,RECURSELOCAL/S,RECURSEGLOBAL/S,EXECUTABLE/K/A,OBJECTS/S,PREFIX/K,INCLUDE/K,SDK/K,CASESENSITIVE/S,NESTEDCOMMENTS/S,MARGIN/N,TABSIZE/N,CONTINUE/S,VERBOSE/S"
  110.  
  111. enum
  112. {
  113.     OPTION_COMPILE,
  114.     OPTION_LINK,
  115.     OPTION_FILES,
  116.     OPTION_IGNORE,
  117.     OPTION_LOCAL,
  118.     OPTION_GLOBAL,
  119.     OPTION_RECURSELOCAL,
  120.     OPTION_RECURSEGLOBAL,
  121.     OPTION_EXECUTABLE,
  122.     OPTION_OBJECTS,
  123.     OPTION_PREFIX,
  124.     OPTION_INCLUDE,
  125.     OPTION_SDK,
  126.     OPTION_CASESENSITIVE,
  127.     OPTION_NESTEDCOMMENTS,
  128.     OPTION_MARGIN,
  129.     OPTION_TABSIZE,
  130.     OPTION_CONTINUE,
  131.     OPTION_VERBOSE,
  132.  
  133.     MAX_ARGS
  134. };
  135.  
  136. ///
  137. /// "structures"
  138.  
  139. /* --------------------------------- ListNode ----------------------------------
  140.  
  141.  All-purpose named-node structure
  142.  
  143. */
  144.  
  145. struct ListNode
  146. {
  147.     struct ListNode *succ;
  148.     char            *name;
  149. };
  150.  
  151. /* ---------------------------------- Options ----------------------------------
  152.  
  153.  Global processing state
  154.  
  155. */
  156.  
  157. struct Options
  158. {
  159.     const char         *compile;                     // compiler command line for compilation
  160.     const char         *link;                        // compiler command line for compilation and linking
  161.     const char         *exec;                        // executable
  162.     const char         *oprefix;                     // object prefix
  163.     const char         *ignore;                      // ignore pattern
  164.  
  165.     struct ListNode    *list_globaldependencies;     // list of global dependencies for the current source code
  166.     struct ListNode    *list_localdependencies;      // list of local  dependencies for the current source file
  167.     struct ListNode    *list_objects;                // list of objects
  168.     struct ListNode    *list_targets;                // list of targets
  169.     struct ListNode    *list_folders;                // list of folders where includes reside
  170.  
  171.     BOOL                generate_objects;            // generate intermediate objects ?
  172.     BOOL                local;                       // consider local  includes ?
  173.     BOOL                global;                      // consider global includes ?
  174.     BOOL                r_local;                     // recursively scan local  includes ?
  175.     BOOL                r_global;                    // recursively scan global includes ?
  176.  
  177.     BOOL                casesensitive;               // file names case sensitive ?
  178.     BOOL                nestedcomments;              // nested comments permitted ?
  179.     BOOL                verbose;                     // verbose ?
  180.     BOOL                fatal;                       // exit on "fatal" errors ?
  181.  
  182.     unsigned int        line;                        // margin
  183.     unsigned int        tab;                         // tab size
  184.  
  185.     char                preparsed[PATH_MAX];         // buffer for preparsed pattern
  186. };
  187.  
  188. /* ---------------------------------- Status -----------------------------------
  189.  
  190.  Parser status used for parsing source code lines
  191.  
  192. */
  193.  
  194. struct Status
  195. {
  196.     unsigned long       line;                        // line number
  197.     BOOL                instring;                    // we are reading a "" string
  198.     BOOL                inconstant;                  // we are reading a '' string
  199.     unsigned short      incomment;                   // level of nested C comments
  200.     BOOL                incommentcpp;                // c++ comment
  201.     unsigned short      inblock;                     // level of nested '{ }' blocks
  202.     unsigned char       ininclude;                   // include (9 if '#include' was readed)
  203.     BOOL                slash;                       // last char was a '/'
  204.     BOOL                star;                        // last char was a '*'
  205.     BOOL                ignore;                      // last char was a '\'
  206. };
  207.  
  208. ///
  209. /// "globals"
  210.  
  211. char cfn[PATH_MAX];                                  // current file name
  212. char cpn[PATH_MAX];                                  // working buffer
  213.  
  214. extern struct Library *DOSBase;
  215.  
  216. ///
  217. /// "prototypes"
  218.  
  219. extern int              AcceptFile         (struct Options *options, int local);
  220. extern void             AddGlobal          (struct Options *options, struct Status *status, int nr);
  221. extern void             AddLocal           (struct Options *options, struct Status *status, int nr);
  222. extern struct ListNode *AddNode            (struct Options *options, struct ListNode **lst, char *x, int end);
  223. extern void             CompletePath       (char *path);
  224. extern struct Parser   *CreateParser       (char *template);
  225. extern struct ListNode *FindNode           (struct Options *options, struct ListNode **lst, const char *x, struct ListNode **prec );
  226. extern void             FreeList           (struct ListNode **lst);
  227. extern void             GenerateTarget     (struct Options *options, const char *dst, int flags);
  228. extern int              LocateInclude      (struct Options *options, int nr);
  229. extern int              main               (int argc, char **argv);
  230. extern int              memicmp            (char *stringA, char *stringB, int length);
  231. extern int              Parse              (struct Parser *parser, char *buffer, int *position, int *results);
  232. extern void             ReadSource         (struct Options *options, const char *x);
  233. extern char            *ReplacePlaceholders(struct Options *options, const char *string, const char *src, const char *exe, const char *obj, const struct ListNode *objs);
  234. extern char            *SkipWS             (char *buffer,  int *position);
  235. extern int              strcmpopt          (const char *y, const char *x, const char **end);
  236. extern void             ValidateFilename   (const char *file);
  237. extern void             WriteString        (struct Options *options, const char *fch, int smartquote);
  238.  
  239. ///
  240. /// "main"
  241.  
  242. /* -----------------------------------------------------------------------------
  243.  
  244.  main entry point
  245.  
  246. */
  247.  
  248. int
  249. main(int argc, char **argv)
  250. {
  251.     struct Options *options;
  252.  
  253.     if (options = (struct Options *)malloc(sizeof(struct Options)))
  254.     {
  255.         LONG           args[MAX_ARGS];
  256.         struct RDArgs *rdArgs;
  257.  
  258.         // set some defaults
  259.  
  260.         memset(options, 0, sizeof(struct Options));
  261.  
  262.         options->compile = COMPILE;
  263.         options->link    = LINK;
  264.         options->line    = DEFLINE;
  265.         options->tab     = DEFTAB;
  266.         options->fatal   = 1;
  267.  
  268.         // read options
  269.  
  270.         memset(args, 0, sizeof(args));
  271.  
  272.         if (rdArgs = ReadArgs(TEMPLATE, args, NULL))
  273.         {
  274.             if (args[OPTION_EXECUTABLE] && args[OPTION_FILES])
  275.             {
  276.                 UBYTE **file;
  277.  
  278.                 if (args[OPTION_VERBOSE])
  279.                 {
  280.                     options->verbose = 1;
  281.  
  282.                     fputs("makemake ©Dietmar Eilert\n", stderr);
  283.                 }
  284.  
  285.                 options->exec = (char *)args[OPTION_EXECUTABLE];
  286.  
  287.                 ValidateFilename(options->exec);
  288.  
  289.                 if (args[OPTION_COMPILE])
  290.  
  291.                     options->compile = (char *)args[OPTION_COMPILE];
  292.  
  293.                 if (args[OPTION_LINK])
  294.  
  295.                     options->link = (char *)args[OPTION_LINK];
  296.  
  297.                 if (args[OPTION_LOCAL])
  298.  
  299.                     options->local = 1;
  300.  
  301.                 if (args[OPTION_GLOBAL])
  302.  
  303.                     options->global = 1;
  304.  
  305.                 if (args[OPTION_RECURSELOCAL])
  306.  
  307.                     options->r_local = 1;
  308.  
  309.                 if (args[OPTION_RECURSEGLOBAL])
  310.  
  311.                     options->r_global = 1;
  312.  
  313.                 if (args[OPTION_PREFIX])
  314.                 {
  315.                     options->oprefix = (char *)args[OPTION_PREFIX];
  316.  
  317.                     ValidateFilename(options->oprefix);
  318.                 }
  319.  
  320.                 if (args[OPTION_INCLUDE])
  321.                 {
  322.                     AddNode(options, &options->list_folders, (char *)args[OPTION_INCLUDE], 1);
  323.                 }
  324.  
  325.                 if (args[OPTION_SDK])
  326.                 {
  327.                     AddNode(options, &options->list_folders, (char *)args[OPTION_SDK], 1);
  328.                 }
  329.  
  330.                 if (args[OPTION_CASESENSITIVE])
  331.  
  332.                     options->casesensitive = 1;
  333.  
  334.                 if (args[OPTION_NESTEDCOMMENTS])
  335.  
  336.                     options->nestedcomments = 1;
  337.  
  338.                 if (args[OPTION_MARGIN])
  339.  
  340.                     options->line = *(LONG *)args[OPTION_MARGIN];
  341.  
  342.                 if (args[OPTION_TABSIZE])
  343.  
  344.                     options->tab = *(LONG *)args[OPTION_TABSIZE];
  345.  
  346.                 if (args[OPTION_CONTINUE])
  347.  
  348.                     options->fatal = 0;
  349.  
  350.                 if (args[OPTION_IGNORE])
  351.                 {
  352.                     int wildcards = (options->casesensitive) ? ParsePattern((char *)args[OPTION_IGNORE], options->preparsed, sizeof(options->preparsed)) : ParsePatternNoCase((char *)args[OPTION_IGNORE], options->preparsed, sizeof(options->preparsed));
  353.  
  354.                     if (wildcards == -1)
  355.                     {
  356.                         fprintf(stderr, "Syntax error in pattern: %s\n", (char *)args[OPTION_IGNORE]);
  357.                     }
  358.                     else
  359.                         options->ignore = (char *)args[OPTION_IGNORE];
  360.                 }
  361.  
  362.                 if (args[OPTION_OBJECTS])
  363.  
  364.                     options->generate_objects = 1;
  365.  
  366.                 // generate makefile
  367.  
  368.                 puts("# makefile for GNU make (automatically generated by makemake)");
  369.  
  370.                 puts("# NOTE: Command lines in GNU makefiles must start with a TAB !\n");
  371.  
  372.                 WriteString(options, "EXE =", FALSE);
  373.  
  374.                 WriteString(options, options->exec, TRUE);
  375.  
  376.                 WriteString(options, NULL, FALSE);
  377.  
  378.                 WriteString(options, NULL, FALSE);
  379.  
  380.                 // generate target "all:"
  381.  
  382.                 if (options->generate_objects)
  383.                 {
  384.                     WriteString(options, "all : $(EXE)", FALSE);
  385.  
  386.                     WriteString(options, NULL, FALSE);
  387.  
  388.                     WriteString(options, NULL, FALSE);
  389.                 }
  390.  
  391.                 for (file = (char **)args[OPTION_FILES]; *file; ++file)
  392.                 {
  393.                     // make objects (as opposed to compiling directly into executable) ?
  394.  
  395.                     if (options->generate_objects)
  396.                     {
  397.                         char *suffix;
  398.  
  399.                         if (strlen(*file) >= PATH_MAX)
  400.                         {
  401.                             fprintf(stderr, "Name is too long: %s\n", *file);
  402.  
  403.                             exit(EXIT_FAILURE);
  404.                         }
  405.  
  406.                         // examine file type
  407.  
  408.                         strcpy(cfn, *file);
  409.  
  410.                         if ((suffix = strrchr(cfn, '.')))
  411.                         {
  412.                             // ignore headers at this point
  413.  
  414.                             if (stricmp(suffix, ".h"))
  415.                             {
  416.                                 // source code (to be compiled) or a file to be linked with ?
  417.  
  418.                                 if (stricmp(suffix, ".c") && stricmp(suffix, ".cxx") && stricmp(suffix, ".cpp") && stricmp(suffix, ".cc") && stricmp(suffix, ".a") && stricmp(suffix, ".asm") && stricmp(suffix, ".a68k"))
  419.                                 {
  420.                                     // to be linked with
  421.  
  422.                                     FILE *fp;
  423.  
  424.                                     if (!(fp = fopen(cfn, "r")))
  425.                                     {
  426.                                         fprintf(stderr, "Can not open %s: %s\n", cfn, strerror(errno));
  427.  
  428.                                         if (options->fatal)
  429.  
  430.                                             exit(EXIT_FAILURE);
  431.                                     }
  432.                                     else
  433.                                         fclose(fp);
  434.  
  435.                                     AddNode(options, &options->list_objects, cfn, 0);
  436.                                 }
  437.                                 else
  438.                                 {
  439.                                     // add source as first dependency
  440.  
  441.                                     AddNode(options, &options->list_localdependencies, *file, 0);
  442.  
  443.                                     // convert suffix to ".o"
  444.  
  445.                                     *suffix = 0;
  446.  
  447.                                     if (strlen(cfn) + 2 >= PATH_MAX)
  448.                                     {
  449.                                         fprintf(stderr, "Name is too long after adding '.o': %s\n", *file);
  450.  
  451.                                         exit(EXIT_FAILURE);
  452.                                     }
  453.  
  454.                                     strcat(cfn, ".o");
  455.  
  456.                                     if (options->oprefix)
  457.                                     {
  458.                                         if (strlen(cfn) + strlen(options->oprefix) >= PATH_MAX)
  459.                                         {
  460.                                             fprintf(stderr, "Name is too long after adding object prefix: %s\n", *file);
  461.  
  462.                                             exit(EXIT_FAILURE);
  463.                                         }
  464.  
  465.                                         strcpy(cpn, options->oprefix);
  466.  
  467.                                         strcat(cpn, cfn);
  468.                                     }
  469.                                     else
  470.                                         strcpy(cpn, cfn);
  471.  
  472.                                     // object not yet generated ?
  473.  
  474.                                     if (!FindNode(options, &options->list_targets, cpn, NULL))
  475.                                     {
  476.                                         struct ListNode *nd = AddNode(options, &options->list_targets, cpn, 0);
  477.  
  478.                                         if (nd == NULL)
  479.  
  480.                                             exit(EXIT_FAILURE);
  481.  
  482.                                         // examine dependencies
  483.  
  484.                                         ReadSource(options, *file);
  485.  
  486.                                         // generate object file
  487.  
  488.                                         GenerateTarget(options, nd->name, GENERATE_OBJECT | GENERATE_FORCE);
  489.  
  490.                                         WriteString(options, NULL, FALSE);
  491.  
  492.                                         // update list of objects
  493.  
  494.                                         AddNode(options, &options->list_objects, nd->name, 0);
  495.                                     }
  496.                                     else
  497.                                     {
  498.                                         // add (existing) object file
  499.  
  500.                                         if (options->verbose)
  501.  
  502.                                             fprintf(stderr, "Generation of %s skipped.\n", cpn);
  503.  
  504.                                         AddNode(options, &options->list_objects, cpn, 0);
  505.                                     }
  506.  
  507.                                 }
  508.                             }
  509.                             else if (options->verbose)
  510.  
  511.                                 fprintf(stderr, "File %s skipped (not a source code).\n", cpn);
  512.                         }
  513.                         else if (options->verbose)
  514.  
  515.                             fprintf(stderr, "File %s skipped (unsupported file suffix).\n", cpn);
  516.                     }
  517.                     else
  518.                     {
  519.                         // find dependancies but do not generate objects (we will later compile directly into executable)
  520.  
  521.                         ReadSource(options, *file);
  522.  
  523.                         AddNode(options, &options->list_objects, *file, 0);
  524.                     }
  525.                 }
  526.  
  527.                 // generate executable
  528.  
  529.                 if (options->list_objects)
  530.  
  531.                     GenerateTarget(options, NULL, GENERATE_EXEC);
  532.  
  533.                 FreeArgs(rdArgs);
  534.  
  535.                 if (options->verbose)
  536.  
  537.                     fputs("Done.\n", stderr);
  538.             }
  539.             else
  540.                 fputs("Required arguments missing !\n", stderr);
  541.         }
  542.         else
  543.             PrintFault(IoErr(), "makemake: ");
  544.  
  545.         free(options);
  546.     }
  547.     else
  548.         fputs("Not enough memory !\n", stderr);
  549.  
  550.     exit(EXIT_SUCCESS);
  551. }
  552.  
  553. ///
  554. /// "lists"
  555.  
  556. /* -----------------------------------------------------------------------------
  557.  
  558.  Find 'name' in 'lst'. Return the pointer to node if it exist or NULL. If 'prec'
  559.  is non-null, the pointer to its predecessor is stored there.
  560.  
  561. */
  562.  
  563. struct ListNode *
  564. FindNode(struct Options *options, struct ListNode **lst, const char *name, struct ListNode **prec)
  565. {
  566.     register struct ListNode *node, *pred;
  567.  
  568.     if (!name)
  569.  
  570.         return(NULL);
  571.  
  572.     for (node = *lst, pred = (struct ListNode *)NULL; node; pred = node, node = node->succ)
  573.     {
  574.         if (options->casesensitive)
  575.         {
  576.             if (!strcmp(name, node->name))
  577.  
  578.                 break;
  579.         }
  580.         else if (!stricmp(name, node->name))
  581.  
  582.             break;
  583.     }
  584.  
  585.     if (prec)
  586.  
  587.         *prec = pred;
  588.  
  589.     return(node);
  590. }
  591.  
  592. /* -----------------------------------------------------------------------------
  593.  
  594.  Add a new data <name to the list <lst>. Set <end>==1 if you want the data to be
  595.  added at THE END of <lst>. If <x> is already in the list, the old one is
  596.  returned. May exit if a new node can't be allocated.
  597.  
  598.  
  599. */
  600.  
  601. struct ListNode *
  602. AddNode(struct Options *options, struct ListNode **lst, char *name, int end)
  603. {
  604.     struct ListNode *new, *pred;
  605.  
  606.     if (!name)
  607.  
  608.         return(NULL);
  609.  
  610.     // entry already exits ?
  611.  
  612.     if (new = FindNode(options, lst, name, &pred))
  613.  
  614.         return(new);
  615.  
  616.     new = malloc(sizeof(struct ListNode));
  617.  
  618.     if (!new)
  619.     {
  620.         fputs("Not enough memory !\n", stderr);
  621.  
  622.         exit(EXIT_FAILURE);
  623.     }
  624.  
  625.     /*  a warning may be added if pred==NULL but, on the other hand, this is a bug and may never be. */
  626.  
  627.     if (end && pred)
  628.     {
  629.         new ->succ = NULL;
  630.  
  631.         pred->succ = new;
  632.     }
  633.     else
  634.     {
  635.         new->succ = *lst;
  636.  
  637.         *lst = new;
  638.     }
  639.  
  640.     if (!(new->name = strdup(name)))
  641.     {
  642.         fputs("Not enough memory !\n", stderr);
  643.  
  644.         exit(EXIT_FAILURE);
  645.     }
  646.  
  647.     return(new);
  648. }
  649.  
  650. /* -----------------------------------------------------------------------------
  651.  
  652.  Free a list of objects allcated with AddNode()
  653.  
  654. */
  655.  
  656. void
  657. FreeList(struct ListNode **lst)
  658. {
  659.     register struct ListNode *node, *succ;
  660.  
  661.     for (node = *lst; node; node = succ)
  662.     {
  663.         if (node->name)
  664.  
  665.             free(node->name);
  666.  
  667.         succ = node->succ;
  668.  
  669.         free(succ);
  670.     }
  671.  
  672.     *lst = NULL;
  673. }
  674.  
  675. ///
  676. /// "io"
  677.  
  678. /* -----------------------------------------------------------------------------
  679.  
  680.  Add string <fch> to the current line. Keep track of output column (note:
  681.  only first character of <string> is checked for TAB and only last
  682.  character is checked for LF). Strings containing spaces are quoted if
  683.  <smartquote> is TRUE.
  684.  
  685. */
  686.  
  687. void
  688. WriteString(struct Options *options, const char *string, int smartquote)
  689. {
  690.     static int column = 0;
  691.  
  692.     // generate empty line if no output string is specified
  693.  
  694.     if (string == NULL)
  695.     {
  696.         puts("");
  697.  
  698.         column = 0;
  699.     }
  700.     else
  701.     {
  702.         int tabsize;
  703.         int len;
  704.         int LF;
  705.         int separator;
  706.  
  707.         // does output start with TAB ?
  708.  
  709.         if (*string == '\t')
  710.         {
  711.             ++string;
  712.  
  713.             tabsize = (options->tab - column % options->tab);
  714.         }
  715.         else
  716.             tabsize = 0;
  717.  
  718.         // if smart quotes are requested, add quotes if string contains spaces
  719.  
  720.         if (smartquote && strchr(string, ' '))
  721.             smartquote = 2;
  722.         else
  723.             smartquote = 0;
  724.  
  725.         // output LF ?
  726.  
  727.         LF = FALSE;
  728.  
  729.         if (len = strlen(string))
  730.         {
  731.             if (string[len - 1] == '\n')
  732.             {
  733.                 LF = TRUE;
  734.  
  735.                 --len;
  736.             }
  737.         }
  738.  
  739.         // continue in new line if output would exeed margin
  740.  
  741.         if ((column + tabsize + len + smartquote) > options->line)
  742.         {
  743.             printf("\\\n");
  744.  
  745.             column = 0;
  746.  
  747.             if (tabsize)
  748.  
  749.                 tabsize = (options->tab - column % options->tab);
  750.         }
  751.  
  752.         if (tabsize)
  753.         {
  754.             putc('\t', stdout);
  755.  
  756.             column += tabsize;
  757.         }
  758.  
  759.         if (smartquote)
  760.         {
  761.             putc('"', stdout);
  762.  
  763.             ++column;
  764.         }
  765.  
  766.         separator = (len != 0);
  767.  
  768.         while (len--)
  769.         {
  770.             putc(*string++, stdout);
  771.  
  772.             ++column;
  773.         }
  774.  
  775.         if (smartquote)
  776.         {
  777.             putc('"', stdout);
  778.  
  779.             ++column;
  780.         }
  781.  
  782.         // start new line after output or continue in this line ?
  783.  
  784.         if (LF)
  785.         {
  786.             putc('\n', stdout);
  787.  
  788.             column = 0;
  789.         }
  790.         else if (separator)
  791.         {
  792.             putc(' ', stdout);
  793.  
  794.             ++column;
  795.         }
  796.     }
  797. }
  798.  
  799. /* -----------------------------------------------------------------------------
  800.  
  801.  Generate next section of makefile for target <dst> (<dst> may be NULL if
  802.  GENERATE_EXEC is set in <flags>, options->exec will be used as target in that
  803.  case).
  804.  
  805. */
  806.  
  807. void
  808. GenerateTarget(struct Options *options, const char *dst, int flags)
  809. {
  810.     // validate target
  811.  
  812.     if (flags & GENERATE_EXEC)
  813.     {
  814.         if (dst == NULL)
  815.  
  816.             dst = options->exec;
  817.     }
  818.  
  819.     if (dst == NULL)
  820.     {
  821.         struct ListNode *nd;
  822.  
  823.         for (nd = options->list_objects; nd; nd = nd->succ)
  824.  
  825.             fprintf(stderr, "WARNING: No target for %s !\n", nd->name);
  826.  
  827.         for (nd = options->list_localdependencies; nd; nd = nd->succ)
  828.  
  829.             fprintf(stderr, "WARNING: No target for %s !\n", nd->name);
  830.  
  831.         for (nd = options->list_globaldependencies; nd; nd = nd->succ)
  832.  
  833.             fprintf(stderr, "WARNING: No target for %s !\n", nd->name);
  834.  
  835.         return;
  836.     }
  837.  
  838.     // update list of targets
  839.  
  840.     if (dst)
  841.     {
  842.         if (flags & GENERATE_FORCE)
  843.         {
  844.             AddNode(options, &options->list_targets, (char *)dst, 0);
  845.         }
  846.         else if (FindNode(options, &options->list_targets, dst, NULL))
  847.         {
  848.             fprintf(stderr, "WARNING: %s generated twice !", dst);
  849.  
  850.             if (options->fatal)
  851.  
  852.                 exit(EXIT_FAILURE);
  853.         }
  854.         else
  855.             AddNode(options, &options->list_targets, (char *)dst, 0);
  856.     }
  857.  
  858.     // generate next section of makefile
  859.  
  860.     if (flags & GENERATE_OBJECT)
  861.     {
  862.         // generate *.o-file from source
  863.  
  864.  
  865.         struct ListNode *nd;
  866.         char            *commandline;
  867.  
  868.         if (options->verbose)
  869.  
  870.             fprintf(stderr, "Generating object %s\n", dst);
  871.  
  872.         WriteString(options, dst, TRUE);
  873.  
  874.         WriteString(options, ":", FALSE);
  875.  
  876.         for (nd = options->list_localdependencies; nd; nd = nd->succ)
  877.  
  878.             WriteString(options, nd->name, TRUE);
  879.  
  880.         for (nd = options->list_globaldependencies; nd; nd = nd->succ)
  881.  
  882.             WriteString(options, nd->name, TRUE);
  883.  
  884.         if (options->list_localdependencies == NULL)
  885.         {
  886.             fputs("Error: Can not generate object without source !\n", stderr);
  887.  
  888.             exit(EXIT_FAILURE);
  889.         }
  890.  
  891.         WriteString(options, NULL, FALSE);
  892.  
  893.         // GNU make requires that commands are indented with a TAB
  894.  
  895.         WriteString(options, "\t", FALSE);
  896.  
  897.         if (commandline = ReplacePlaceholders(options, options->compile, options->list_localdependencies->name, NULL, dst, NULL))
  898.         {
  899.             WriteString(options, commandline, FALSE);
  900.  
  901.             free(commandline);
  902.         }
  903.  
  904.         WriteString(options, NULL, FALSE);
  905.     }
  906.     else
  907.     {
  908.         // generate executable
  909.  
  910.         struct ListNode *nd;
  911.         char            *commandline;
  912.  
  913.         if (options->verbose)
  914.  
  915.             fputs("Generating executable\n", stderr);
  916.  
  917.         if (stricmp(dst, options->exec) == 0)
  918.  
  919.             dst = "$(EXE)";
  920.  
  921.         WriteString(options, dst, TRUE);
  922.  
  923.         WriteString(options, ":", FALSE);
  924.  
  925.         for (nd = options->list_objects; nd; nd = nd->succ)
  926.  
  927.             WriteString(options, nd->name, TRUE);    // sources
  928.  
  929.         for (nd = options->list_localdependencies; nd; nd = nd->succ)
  930.  
  931.             WriteString(options, nd->name, TRUE);    // local includes
  932.  
  933.         for (nd = options->list_globaldependencies; nd; nd = nd->succ)
  934.  
  935.             WriteString(options, nd->name, TRUE);    // global includes
  936.  
  937.         WriteString(options, NULL, FALSE);
  938.  
  939.         // GNU make requires that commands are indented with a TAB
  940.  
  941.         WriteString(options, "\t", FALSE);
  942.  
  943.         if (commandline = ReplacePlaceholders(options, options->link, NULL, dst, NULL, options->list_objects))
  944.         {
  945.             WriteString(options, commandline, FALSE);
  946.  
  947.             free(commandline);
  948.         }
  949.  
  950.         WriteString(options, NULL, FALSE);
  951.  
  952.         FreeList(&options->list_objects);            // destroy source file for this target
  953.     }
  954.  
  955.     // processed, all dependencies may be destroyed
  956.  
  957.     FreeList(&options->list_globaldependencies);
  958.  
  959.     FreeList(&options->list_localdependencies);
  960. }
  961.  
  962. /* -----------------------------------------------------------------------------
  963.  
  964.  Look in context if the file <cfn> may or may not be processed. Current context
  965.  <options> is "local" (<locale>==1) or "global" (<local>==0). Result: 1 (accept
  966.  file) or 0 (ignore file).
  967.  
  968. */
  969.  
  970. int
  971. AcceptFile(struct Options *options, int local)
  972. {
  973.     // ignore this file ?
  974.  
  975.     if (options->ignore)
  976.     {
  977.         int reject = (options->casesensitive) ? MatchPattern(options->preparsed, cfn) : MatchPatternNoCase(options->preparsed, cfn);
  978.  
  979.         if (reject)
  980.  
  981.             return(0);
  982.     }
  983.  
  984.     if (local)
  985.     {
  986.         if (options->local)
  987.  
  988.             return(1);
  989.     }
  990.     else if (options->global)
  991.     {
  992.         return(1);
  993.     }
  994.     else
  995.         return(0);
  996. }
  997.  
  998. /* -----------------------------------------------------------------------------
  999.  
  1000.  Look for an include file (cfn) in all paths in options->list_folders. Result: 1
  1001.  if the file can be found (the result is in cpn) or 0 if the file can not be
  1002.  found (cpn is invalid).
  1003.  
  1004. */
  1005.  
  1006. int
  1007. LocateInclude(struct Options *options, int nr)
  1008. {
  1009.     register struct ListNode *nd;
  1010.  
  1011.     int fl = strlen(cfn);
  1012.  
  1013.     for (nd = options->list_folders; nd; nd = nd->succ)
  1014.     {
  1015.         if (fl + strlen(nd->name) >= PATH_MAX)
  1016.         {
  1017.             fprintf(stderr, "Warning: path is too long (and ignored).\n'%s%s'\n", nd->name, cfn);
  1018.         }
  1019.         else
  1020.         {
  1021.             strcpy(cpn, nd->name);
  1022.  
  1023.             CompletePath(cpn);
  1024.  
  1025.             strcat(cpn, cfn);
  1026.  
  1027.             if (options->verbose)
  1028.             {
  1029.                 int i;
  1030.  
  1031.                 for (i = nr; i > 1; i--)
  1032.  
  1033.                     fputs("-", stderr);
  1034.  
  1035.                 fprintf(stderr, "-> Looking for %s", cpn);
  1036.             }
  1037.  
  1038.             if (access(cpn, 0) == 0)
  1039.             {
  1040.                 if (options->verbose)
  1041.  
  1042.                     fputs(" found.\n", stderr);
  1043.  
  1044.                 return(1);
  1045.  
  1046.             }
  1047.             else if (options->verbose)
  1048.  
  1049.                 fputs(" not found.\n", stderr);
  1050.         }
  1051.     }
  1052.  
  1053.     return(0);
  1054. }
  1055.  
  1056. void
  1057. AddGlobal(struct Options *options, struct Status *status, int nr)
  1058. {
  1059.     if (AcceptFile(options, 0))
  1060.     {
  1061.         if (LocateInclude(options, nr))
  1062.         {
  1063.             if (options->r_global)
  1064.             {
  1065.                 // already processed ?
  1066.  
  1067.                 if (!FindNode(options, &options->list_globaldependencies, cpn, NULL))
  1068.                 {
  1069.                     struct ListNode *nd = AddNode(options, &options->list_globaldependencies, cpn, 0);
  1070.  
  1071.                     if (nd)
  1072.                     {
  1073.                         ReadSource(options,nd->name);
  1074.                     }
  1075.                     else
  1076.                         exit(EXIT_FAILURE);
  1077.                 }
  1078.             }
  1079.             else
  1080.                 AddNode(options, &options->list_globaldependencies, cpn, 0);
  1081.         }
  1082.         else
  1083.         {
  1084.             fprintf(stderr, "%s (line %d): Can  not locate %s !\n", cfn, status->line, cfn);
  1085.  
  1086.             if (options->fatal)
  1087.                 exit(EXIT_FAILURE);
  1088.             else
  1089.                 printf("# Warning: %s can not be located !\n", cfn);
  1090.         }
  1091.     }
  1092. }
  1093.  
  1094. void
  1095. AddLocal(struct Options *options, struct Status *status, int nr)
  1096. {
  1097.     if (AcceptFile(options, 1))
  1098.     {
  1099.         if (access(cfn, 0))
  1100.         {
  1101.             fprintf(stderr, "%s (line %d): Can  not locate %s !\n", cfn, status->line, cfn);
  1102.  
  1103.             if (options->fatal)
  1104.                 exit(EXIT_FAILURE);
  1105.             else
  1106.                 printf("# Warning: %s can not be located !\n", cfn);
  1107.         }
  1108.         else
  1109.         {
  1110.             if (options->r_local)
  1111.             {
  1112.                 // already processed ?
  1113.  
  1114.                 if (!FindNode(options, &options->list_localdependencies, cfn, NULL))
  1115.                 {
  1116.                     struct ListNode *nd = AddNode(options, &options->list_localdependencies, cfn, 1);
  1117.  
  1118.                     strcpy(cpn, cfn);
  1119.  
  1120.                     if (nd)
  1121.                     {
  1122.                         ReadSource(options, nd->name);
  1123.                     }
  1124.                     else
  1125.                         exit(EXIT_FAILURE);
  1126.                 }
  1127.             }
  1128.             else
  1129.                 AddNode(options, &options->list_localdependencies, cfn, 1);
  1130.         }
  1131.     }
  1132. }
  1133.  
  1134. /* -----------------------------------------------------------------------------
  1135.  
  1136.  Read source code
  1137.  
  1138. */
  1139.  
  1140. void
  1141. ReadSource(struct Options *options, const char *file)
  1142. {
  1143.     // # of recursion
  1144.  
  1145.     static unsigned int nbre_rec = 0;
  1146.  
  1147.     struct Status  status = { 0 };
  1148.     int            i;
  1149.     FILE          *fp;
  1150.     char           c;
  1151.     int            len;
  1152.  
  1153.     if (fp = fopen(file, "r"))
  1154.     {
  1155.         if (options->verbose)
  1156.         {
  1157.             // indent according to nesting level
  1158.  
  1159.             for (i = ++nbre_rec; i > 1 && options->verbose; i--)
  1160.  
  1161.                 fputs(" ", stderr);
  1162.  
  1163.             fprintf(stderr, "Reading %s\n", file);
  1164.         }
  1165.  
  1166.         status.line = 1;
  1167.  
  1168.         len = 0;
  1169.  
  1170.         while ((c = fgetc(fp)) != EOF)
  1171.         {
  1172.             if (status.ininclude)
  1173.             {
  1174.                 // reading content after "#"
  1175.  
  1176.                 if (status.ininclude == 9)
  1177.                 {
  1178.                     // reading file name after "#include <"
  1179.  
  1180.                     if (len > PATH_MAX)
  1181.                     {
  1182.                         fputs("FATAL ERROR: FILE NAME TOO LONG !\N", stderr);
  1183.  
  1184.                         exit(EXIT_FAILURE);
  1185.                     }
  1186.  
  1187.                     // no interpretation of the name is done as it is system dependant
  1188.  
  1189.                     switch (c)
  1190.                     { 
  1191.                         case '\n':
  1192.  
  1193.                             fprintf(stderr, "%s: Unterminated #include in line %ld !\n", file, status.line);
  1194.  
  1195.                             exit(EXIT_FAILURE);
  1196.  
  1197.                         case '"':
  1198.  
  1199.                             // it's a local include
  1200.  
  1201.                             if (status.instring)
  1202.                             {
  1203.                                 cfn[len] = 0;
  1204.  
  1205.                                 AddLocal(options, &status, nbre_rec);
  1206.  
  1207.                                 status.instring  = FALSE;
  1208.                                 status.ininclude = FALSE;
  1209.                             }
  1210.                             else
  1211.                                 cfn[len++] = c;
  1212.  
  1213.                             break;
  1214.  
  1215.                         case '>':
  1216.  
  1217.                             // it's a global include
  1218.  
  1219.                             if (status.instring == FALSE)
  1220.                             {  
  1221.                                 cfn[len] = 0;
  1222.  
  1223.                                 AddGlobal(options, &status, nbre_rec);
  1224.  
  1225.                                 status.ininclude = FALSE;
  1226.                             }
  1227.                             else
  1228.                                 cfn[len++] = c;
  1229.  
  1230.                             break;
  1231.  
  1232.                         default:
  1233.  
  1234.                             cfn[len++] = c;
  1235.                     }
  1236.  
  1237.                     if (len >= PATH_MAX)
  1238.                     {
  1239.                         fprintf(stderr, "%s: #include filename too long in line %ld !\n", file, status.line);
  1240.  
  1241.                         exit(EXIT_FAILURE);
  1242.                     }
  1243.                 }
  1244.                 else
  1245.                 {
  1246.                     // somewhere in "#include <"
  1247.  
  1248.                     switch (c) {
  1249.  
  1250.                         case 'i':
  1251.  
  1252.                             if (status.ininclude != 1)
  1253.  
  1254.                                 goto autre;
  1255.  
  1256.                             ++status.ininclude;
  1257.  
  1258.                             break;
  1259.  
  1260.                         case 'n':
  1261.  
  1262.                             if (status.ininclude != 2)
  1263.  
  1264.                                 goto autre;
  1265.  
  1266.                             ++status.ininclude;
  1267.  
  1268.                             break;
  1269.  
  1270.                         case 'c':
  1271.  
  1272.                             if (status.ininclude != 3)
  1273.  
  1274.                                 goto autre;
  1275.  
  1276.                             ++status.ininclude;
  1277.  
  1278.                             break;
  1279.  
  1280.                         case 'l':
  1281.  
  1282.                             if (status.ininclude != 4)
  1283.  
  1284.                                 goto autre;
  1285.  
  1286.                             ++status.ininclude;
  1287.  
  1288.                             break;
  1289.  
  1290.                         case 'u':
  1291.  
  1292.                             if (status.ininclude != 5)
  1293.  
  1294.                                 goto autre;
  1295.  
  1296.                             ++status.ininclude;
  1297.  
  1298.                             break;
  1299.                         case 'd':
  1300.  
  1301.                             if (status.ininclude != 6)
  1302.  
  1303.                                 goto autre;
  1304.  
  1305.                             ++status.ininclude;
  1306.  
  1307.                             break;
  1308.  
  1309.                         case 'e':
  1310.  
  1311.                             if (status.ininclude != 7)
  1312.  
  1313.                                 goto autre;
  1314.  
  1315.                             ++status.ininclude;
  1316.  
  1317.                             break;
  1318.  
  1319.                         case '\t':
  1320.                         case ' ':
  1321.  
  1322.                             if ((status.ininclude != 8) && (status.ininclude != 1))
  1323.  
  1324.                                 goto autre;
  1325.  
  1326.                             break;
  1327.  
  1328.                         case '<':
  1329.  
  1330.                             if (status.ininclude != 8)
  1331.  
  1332.                                 goto autre;
  1333.  
  1334.                             ++status.ininclude;
  1335.  
  1336.                             len = 0;
  1337.  
  1338.                             break;
  1339.  
  1340.                         case '"':
  1341.  
  1342.                             if (status.ininclude != 8)
  1343.  
  1344.                                 goto autre;
  1345.  
  1346.                             ++status.ininclude;
  1347.  
  1348.                             status.instring = 1;
  1349.  
  1350.                             len = 0;
  1351.  
  1352.                             break;
  1353.  
  1354.                         default :
  1355.  
  1356.                             goto autre;
  1357.                     }
  1358.                 }
  1359.             }
  1360.             else if (status.instring || status.inconstant)
  1361.             {
  1362.                 // reading a string or string constant
  1363.  
  1364.                 switch (c)
  1365.                 {
  1366.                     case '\n':
  1367.  
  1368.                         fprintf(stderr, "%s: Unterminated string in line %ld !\n", file, status.line);
  1369.  
  1370.                         exit(EXIT_FAILURE);
  1371.  
  1372.                     case '\\':
  1373.  
  1374.                         // ignore next character (unless preced by \)
  1375.  
  1376.                         if (status.ignore)
  1377.                             status.ignore = 0;
  1378.                         else
  1379.                             status.ignore = 1;
  1380.  
  1381.                         break;
  1382.  
  1383.                     case '"':
  1384.  
  1385.                         if (status.instring && !status.ignore)
  1386.                             status.instring = 0;
  1387.                         else
  1388.                             status.ignore = 0;
  1389.  
  1390.                         break;
  1391.  
  1392.                     case '\'':
  1393.  
  1394.                         if (status.inconstant && !status.ignore)
  1395.                             status.inconstant = 0;
  1396.                         else
  1397.                             status.ignore = 0;
  1398.  
  1399.                         break;
  1400.  
  1401.                     default:
  1402.  
  1403.                         status.ignore = 0;
  1404.                 }
  1405.             }
  1406.             else if (status.incommentcpp)
  1407.             {
  1408.                 // reading a C++ comment
  1409.  
  1410.                 if (c == '\n')
  1411.                 {
  1412.                     status.incommentcpp = 0;
  1413.  
  1414.                     ++status.line;
  1415.                 }
  1416.             }
  1417.             else if (status.incomment)
  1418.             {
  1419.                 // reading a C comment
  1420.  
  1421.                 if (c == '\n')
  1422.                 {
  1423.                     ++status.line;
  1424.  
  1425.                     status.star = 0;
  1426.  
  1427.                 }
  1428.                 else if (c == '*')
  1429.                 {
  1430.                     // nesting ?
  1431.  
  1432.                     if (status.slash)
  1433.                     {
  1434.                         status.slash = 0;
  1435.  
  1436.                         if (options->nestedcomments == FALSE)
  1437.                         {
  1438.                             fprintf(stderr, "%s: Nested comments not allowed (line %ld) !\n", file, status.line);
  1439.  
  1440.                             exit(EXIT_FAILURE);
  1441.                         }
  1442.                         else
  1443.                             ++status.incomment;
  1444.  
  1445.                         status.star = 0;
  1446.                     }
  1447.                     else
  1448.                         status.star = 1;
  1449.                 }
  1450.                 else if (c == '/')
  1451.                 {
  1452.                     if (status.star)
  1453.                     {
  1454.                         status.star  = 0;
  1455.                         status.slash = 0;
  1456.  
  1457.                         --status.incomment;
  1458.                     }
  1459.                     else
  1460.                         status.slash = 1;
  1461.                 }
  1462.                 else
  1463.                 {
  1464.                     status.star  = 0;
  1465.                     status.slash = 0;
  1466.                 }
  1467.             }
  1468.             else if (status.ignore)
  1469.             {
  1470.                 status.ignore = 0;
  1471.  
  1472.                 if (c == '\n')
  1473.  
  1474.                     ++status.line;
  1475.             }
  1476.             else
  1477.             {
  1478.                 // plain source code
  1479.  
  1480.                 autre:
  1481.  
  1482.                 status.ininclude = 0;
  1483.  
  1484.                 switch (c) {
  1485.  
  1486.                     case '/':
  1487.  
  1488.                         // a c++ comment ?
  1489.  
  1490.                         if (status.slash)
  1491.                         {
  1492.                             status.slash       = 0;
  1493.                             status.incommentcpp  = 1;
  1494.                         }
  1495.                         else if (status.star)
  1496.                         {
  1497.                             fprintf(stderr, "%s: Unexpected */ in line %ld !\n", file, status.line);
  1498.  
  1499.                             exit(EXIT_FAILURE);
  1500.                         }
  1501.                         else
  1502.                             status.slash = 1;
  1503.  
  1504.                         break;
  1505.  
  1506.                     case '*':
  1507.  
  1508.                         // opening new comment ?
  1509.  
  1510.                         if (status.slash)
  1511.                         {
  1512.                             status.slash = 0;
  1513.  
  1514.                             if ((++status.incomment > 1) && (options->nestedcomments == FALSE))
  1515.                             {
  1516.                                 fprintf(stderr, "%s: Nested comments not allowed (line %ld) !\n", file, status.line);
  1517.  
  1518.                                 exit(EXIT_FAILURE);
  1519.                             }
  1520.                         }
  1521.                         else
  1522.                             status.star = 1;
  1523.  
  1524.                         break;
  1525.  
  1526.                     case '\n':
  1527.  
  1528.                         ++status.line;
  1529.  
  1530.                         status.star  = 0;
  1531.                         status.slash = 0;
  1532.  
  1533.                         break;
  1534.  
  1535.                     case '\\':
  1536.  
  1537.                         status.ignore = 1;
  1538.                         status.star   = 0;
  1539.                         status.slash  = 0;
  1540.  
  1541.                         break;
  1542.  
  1543.                     case '\'':
  1544.  
  1545.                         status.inconstant = 1;
  1546.                         status.star  = 0;
  1547.                         status.slash = 0;
  1548.  
  1549.                         break;
  1550.  
  1551.                     case '"':
  1552.  
  1553.                         status.instring = 1;
  1554.                         status.star  = 0;
  1555.                         status.slash = 0;
  1556.  
  1557.                         break;
  1558.  
  1559.                     case '{':
  1560.  
  1561.                         ++status.inblock;
  1562.  
  1563.                         status.star  = 0 ;
  1564.                         status.slash = 0;
  1565.  
  1566.                         break;
  1567.  
  1568.                     case '}':
  1569.  
  1570.                         if (!status.inblock)
  1571.                         {
  1572.                             fprintf(stderr, "%s: Unexpected } in line %d\n", file, status.line);
  1573.  
  1574.                             exit(EXIT_FAILURE);
  1575.  
  1576.                         }
  1577.                         else
  1578.                             --status.inblock;
  1579.  
  1580.                         status.star  = 0 ;
  1581.                         status.slash = 0;
  1582.  
  1583.                         break;
  1584.  
  1585.                     case '#':
  1586.  
  1587.                         status.star      = 0;
  1588.                         status.slash     = 0;
  1589.                         status.ininclude = 1;
  1590.  
  1591.                         break;
  1592.  
  1593.                     default:
  1594.  
  1595.                         status.star      = 0;
  1596.                         status.slash     = 0;
  1597.                         status.ininclude = 0;
  1598.                 }
  1599.             }
  1600.         }
  1601.  
  1602.         fclose(fp);
  1603.  
  1604.         --nbre_rec;
  1605.  
  1606.         if (status.inblock)
  1607.         {
  1608.             fprintf(stderr, "%s: %ld pending block(s) !\n", file, status.inblock);
  1609.  
  1610.             if (options->fatal)
  1611.  
  1612.                 exit(EXIT_FAILURE);
  1613.         }
  1614.  
  1615.         if (status.incomment)
  1616.         {
  1617.             fprintf(stderr, "%s : %ld pending C comment(s) !\n", file, status.incomment);
  1618.  
  1619.             if (options->fatal)
  1620.  
  1621.                 exit(EXIT_FAILURE);
  1622.         }
  1623.  
  1624.         if (status.instring || status.inconstant)
  1625.         {
  1626.             fprintf(stderr, "%s: Unterminated string(s)", file);
  1627.  
  1628.             if (options->fatal)
  1629.  
  1630.                 exit(EXIT_FAILURE);
  1631.         }
  1632.  
  1633.         if (status.ininclude == 9)
  1634.         {
  1635.             fprintf(stderr, "%s : Unexpected end of file when reading #include directive !\n", file);
  1636.  
  1637.             if (options->fatal)
  1638.  
  1639.                 exit(EXIT_FAILURE);
  1640.         }
  1641.     }
  1642.     else
  1643.     {
  1644.         fprintf(stderr, "Can not open %s: %s\n", file, strerror(errno));
  1645.  
  1646.         if (options->fatal)
  1647.  
  1648.             exit(EXIT_FAILURE);
  1649.     }
  1650. }
  1651.  
  1652. /* -----------------------------------------------------------------------------
  1653.  
  1654.  Like strcmp() but considers length of <x> only. Stores pointer to first
  1655.  character of <y> which is not in 'x' in <end> if strings match up to the length
  1656.  of <x>. function succeeds).
  1657.  
  1658. */
  1659.  
  1660. int
  1661. strcmpopt(const char *y, const char *x, const char **end)
  1662. {
  1663.     for (; *x; x++, y++)
  1664.  
  1665.         if (*x != *y)
  1666.  
  1667.             return(*x - *y);
  1668.  
  1669.     if (end)
  1670.  
  1671.         *end = y;
  1672.  
  1673.     return(0);
  1674. }
  1675.  
  1676. /* -----------------------------------------------------------------------------
  1677.  
  1678.  Some systems (like AmigaDOS) use ':' as special separator in filename (i.e.
  1679.  after drivename). This may confuse 'make' so we display a warning.
  1680.  
  1681. */
  1682.  
  1683. void
  1684. ValidateFilename(const char *file)
  1685. {
  1686.     if (strchr(file, ':'))
  1687.  
  1688.         fprintf(stderr, "Warning: ':' in file names may confuse make (%s) !\n", file);
  1689. }
  1690.  
  1691. /* ------------------------------- CompletePath --------------------------------
  1692.  
  1693.  Add trailing "/" to path (unless already terminated by "/" or ":")
  1694.  
  1695. */
  1696.  
  1697. void
  1698. CompletePath(char *path)
  1699. {
  1700.     if (*path)
  1701.     {
  1702.         path = strchr(path, 0) - 1;
  1703.     }
  1704.  
  1705.     if ((*path != '/') && (*path != ':'))
  1706.  
  1707.         strcat(path, "/");
  1708. }
  1709.  
  1710. ///
  1711. /// "strings"
  1712.  
  1713. /* ---------------------------- ReplacePlaceholders ----------------------------
  1714.  
  1715.  Replace placeholders (%exe, %src, %obj, %objs) in <string>
  1716. */
  1717.  
  1718. char *
  1719. ReplacePlaceholders(struct Options *options, const char *string, const char *src, const char *exe, const char *obj, const struct ListNode *objs)
  1720. {
  1721.     char *buffer;
  1722.     int   len;
  1723.  
  1724.     if (len = strlen(string))
  1725.     {
  1726.         int freebuffer;
  1727.         int buffersize;
  1728.  
  1729.         freebuffer = 512;
  1730.         buffersize = 512 + (++len);
  1731.  
  1732.         // duplicate string
  1733.  
  1734.         if (buffer = (char *)malloc(buffersize))
  1735.         {
  1736.             char *placeholder;
  1737.  
  1738.             strcpy(buffer, string);
  1739.  
  1740.             do
  1741.             {
  1742.                 struct ListNode *replacements;
  1743.                 char            *replacement;
  1744.                 int              placeholdersize;
  1745.  
  1746.                 replacements = NULL;
  1747.                 replacement  = NULL;
  1748.  
  1749.                 // locate next placeholder
  1750.  
  1751.                 placeholdersize = 4;
  1752.  
  1753.                 if (placeholder = strstr(buffer, "%objs"))
  1754.                 {
  1755.                     replacements = (struct ListNode *)objs;
  1756.  
  1757.                     placeholdersize = 5;
  1758.                 }
  1759.                 else if (placeholder = strstr(buffer, "%exe"))
  1760.                 {
  1761.                     replacement = (char *)exe;
  1762.                 }
  1763.                 else if (placeholder = strstr(buffer, "%src"))
  1764.                 {
  1765.                     replacement = (char *)src;
  1766.                 }
  1767.                 else if (placeholder = strstr(buffer, "%obj"))
  1768.  
  1769.                     replacement = (char *)obj;
  1770.  
  1771.                 if (placeholder)
  1772.                 {
  1773.                     // remove placeholder
  1774.  
  1775.                     memmove(placeholder, placeholder + placeholdersize, buffersize - freebuffer - (placeholder - buffer) - placeholdersize);
  1776.  
  1777.                     freebuffer += placeholdersize;
  1778.  
  1779.                     if (replacement || replacements)
  1780.                     {
  1781.                         int count = 0;
  1782.  
  1783.                         // insert replacement(s)
  1784.  
  1785.                         do
  1786.                         {
  1787.                             if (replacements)
  1788.  
  1789.                                 replacement = replacements->name;
  1790.  
  1791.                             if (replacement)
  1792.                             {
  1793.                                 int replacementsize;
  1794.                                 int space;
  1795.  
  1796.                                 replacementsize = strlen(replacement);
  1797.  
  1798.                                 // add separator before 2nd, 3rd, ... entry
  1799.  
  1800.                                 space = (++count == 1) ? 0 : 1;
  1801.  
  1802.                                 // enlarge buffer as needed
  1803.  
  1804.                                 if (freebuffer < (replacementsize + space))
  1805.                                 {
  1806.                                     if (buffer = (char *)realloc(buffer, buffersize + PATH_MAX))
  1807.                                     {
  1808.                                         freebuffer += PATH_MAX;
  1809.                                         buffersize += PATH_MAX;
  1810.                                     }
  1811.                                     else
  1812.                                         break;
  1813.                                 }
  1814.  
  1815.                                 // make room
  1816.  
  1817.                                 memmove(placeholder + replacementsize + space, placeholder, buffersize - freebuffer - (placeholder - buffer));
  1818.  
  1819.                                 // insert replacement
  1820.  
  1821.                                 memmove(placeholder, replacement, replacementsize);
  1822.  
  1823.                                 freebuffer -= replacementsize;
  1824.                                 freebuffer -= space;
  1825.  
  1826.                                 while (space--)
  1827.  
  1828.                                     placeholder[replacementsize + space] = 32;
  1829.                             }
  1830.  
  1831.                             if (replacements)
  1832.  
  1833.                                 replacements = replacements->succ;
  1834.  
  1835.                         } while (replacements);
  1836.                     }
  1837.                 }
  1838.  
  1839.             } while (placeholder);
  1840.         }
  1841.     }
  1842.     else
  1843.         buffer = NULL;
  1844.  
  1845.     return(buffer);
  1846. }
  1847.  
  1848. ///
  1849.